using System;
using System.Reflection;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace Granite.Wcf.PocoService
{
	class OperationInvoker : IOperationBehavior, IOperationInvoker
	{
		// Simple invoker, simply delegates to the underlying MethodInfo object
		readonly MethodInfo method;

		public OperationInvoker(MethodInfo method)
		{
			this.method = method;
		}

		/// <summary>
		/// Gets a value that specifies whether the <see cref="M:System.ServiceModel.Dispatcher.IOperationInvoker.Invoke(System.Object,System.Object[],System.Object[]@)" /> or <see cref="M:System.ServiceModel.Dispatcher.IOperationInvoker.InvokeBegin(System.Object,System.Object[],System.AsyncCallback,System.Object)" /> method is called by the dispatcher.
		/// </summary>
		/// <returns>
		/// true if the dispatcher invokes the synchronous operation; otherwise, false.
		/// </returns>
		public bool IsSynchronous
		{
			get { return true; }
		}

		/// <summary>
		/// Implement to pass data at runtime to bindings to support custom behavior.
		/// </summary>
		/// <param name="operationDescription">
		/// The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.
		/// </param>
		/// <param name="bindingParameters">
		/// The collection of objects that binding elements require to support the behavior.
		/// </param>
		public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
		{
		}

		/// <summary>
		/// Returns an <see cref="T:System.Array" /> of parameter objects.
		/// </summary>
		/// <returns>
		/// The parameters that are to be used as arguments to the operation.
		/// </returns>
		public object[] AllocateInputs()
		{
			return new object[method.GetParameters().Length];
		}

		/// <summary>
		/// Implements a modification or extension of the client across an operation.
		/// </summary>
		/// <param name="operationDescription">
		/// The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.
		/// </param>
		/// <param name="clientOperation">
		/// The run-time object that exposes customization properties for the operation described by <paramref name="operationDescription" />.
		/// </param>
		public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
		{
		}

		/// <summary>
		/// Implements a modification or extension of the service across an operation.
		/// </summary>
		/// <param name="operationDescription">
		/// The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.
		/// </param>
		/// <param name="dispatchOperation">
		/// The run-time object that exposes customization properties for the operation described by <paramref name="operationDescription" />.
		/// </param>
		public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
		{
			dispatchOperation.Invoker = this;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="instance"></param>
		/// <param name="inputs"></param>
		/// <param name="outputs"></param>
		/// <returns></returns>
		public object Invoke(object instance, object[] inputs, out object[] outputs)
		{
			outputs = new object[0];
			return method.Invoke(instance, inputs);
		}

		/// <summary>
		/// An asynchronous implementation of the <see cref="M:System.ServiceModel.Dispatcher.IOperationInvoker.Invoke(System.Object,System.Object[],System.Object[]@)" /> method.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.IAsyncResult" /> used to complete the asynchronous call.
		/// </returns>
		/// <param name="instance">
		/// The object to be invoked.
		/// </param>
		/// <param name="inputs">
		/// The inputs to the method.
		/// </param>
		/// <param name="callback">
		/// The asynchronous callback object.
		/// </param>
		/// <param name="state">
		/// Associated state data.
		/// </param>
		public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="instance"></param>
		/// <param name="outputs"></param>
		/// <param name="result"></param>
		/// <returns></returns>
		public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
		{
			throw new NotSupportedException();
		}

		/// <summary>
		/// Implement to confirm that the operation meets some intended criteria.
		/// </summary>
		/// <param name="operationDescription">
		/// The operation being examined. Use for examination only. If the operation description is modified, the results are undefined.
		/// </param>
		public void Validate(OperationDescription operationDescription)
		{
		}

	}
}
